/* Vecmath.

   Copyright (C) 2001, 2002, 2003 Stefan Maierhofer.

   Written by Stefan Maierhofer <sm@cg.tuwien.ac.at>

   This file is part of Vecmath.

   Vecmath is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   Vecmath is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with Vecmath; if not, write to the Free Software Foundation,
   Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */

using System;
using NUnit.Framework;

namespace Vecmath
{

    /// <summary>
    /// Shift3D.
    /// </summary>
    public struct Shift3D
    {

        public static Shift3D Identity = new Shift3D(0,0,0);

        public Shift3D(double x, double y, double z)
        {
            v = new Vec3D(x,y,z);
        }

        public Shift3D(Vec3D shift)
        {
            v = shift;
        }

        public double x { get { return v._x[0]; } }
        public double y { get { return v._x[1]; } }
        public double z { get { return v._x[2]; } }

        public Trafo3D ToTrafo3D()
        {
            return new Trafo3D(
                1, 0, 0, 0,
                0, 1, 0, 0,
                0, 0, 1, 0,
                v._x[0], v._x[1], v._x[2], 1
                );
        }

        public static implicit operator Trafo3D(Shift3D r)
        {
            return r.ToTrafo3D();
        }

        public static Shift3D operator*(Shift3D a, Shift3D b)
        {
            return new Shift3D(a.v + b.v);
        }

        public static Trafo3D operator*(Scale3D a, Shift3D b)
        {
            return new Trafo3D(
                a.x, 0, 0, 0,
                0, a.y, 0, 0,
                0, 0, a.z, 0,
                b.x, b.y, b.z, 1
                );
        }

        public static Trafo3D operator*(Rot3D a, Shift3D b)
        {
            return a.ToTrafo3D() * b.ToTrafo3D();
        }

        public static Trafo3D operator*(Trafo3D a, Shift3D b)
        {
            a._x[12] += b.x;
            a._x[13] += b.y;
            a._x[14] += b.z;
            return a;
        }

        public static Vec3D operator*(Vec3D v, Shift3D t)
        {
            return v;
        }

        public static Pnt3D operator*(Pnt3D p, Shift3D t)
        {
            return p + t.v;
        }

        public static Ray3D operator*(Ray3D r, Shift3D t)
        {
            return new Ray3D(r.p * t, r.v * t);
        }

        public static Box3D operator*(Box3D b, Shift3D t)
        {
            return new Box3D(b.Lower + t.v, b.Upper + t.v);
        }

        internal Vec3D v;

    }


    [TestFixture]
    public class Shift3DTest
    {
        [Test]
        public void MulVec3D()
        {
            Vec3D v = new Vec3D(1,2,3);
            Shift3D t = new Shift3D(1,2,3);
            Assert.AreEqual(new Vec3D(1,2,3), v * t);
        }

        [Test]
        public void MulPnt3D()
        {
            Pnt3D p = new Pnt3D(1,2,3);
            Shift3D t = new Shift3D(1,2,3);
            Assert.AreEqual(new Pnt3D(2,4,6), p * t);
        }

        [Test]
        public void MulBox3D()
        {
            Box3D b = new Box3D(new Pnt3D(-1, -1, -1), new Pnt3D(1,1,1));
            Shift3D t = new Shift3D(1,2,3);
            Assert.AreEqual(
                new Box3D(new Pnt3D(0, 1, 2), new Pnt3D(2, 3, 4)),
                b * t
                );
        }
    }

}
